package com.qqt.csr.archive.service;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.qqt.csr.archive.assembler.ConversationArchiveAssembler;
import com.qqt.csr.archive.entity.reader.CsrImAccount;
import com.qqt.csr.archive.entity.writer.ArchiveConversation;
import com.qqt.csr.archive.entity.writer.ArchiveMessage;
import com.qqt.csr.archive.enums.ConversationType;
import com.qqt.csr.archive.enums.RequestSource;
import com.qqt.csr.archive.mapper.ArchiveConversationMapper;
import com.qqt.csr.archive.request.ArchiveConversationPageQueryRequest;
import com.qqt.csr.archive.response.ArchiveConversationDetailResponse;
import com.qqt.csr.archive.response.ArchiveConversationResponse;
import com.qqt.csr.archive.response.ArchiveMessageResponse;
import com.qqt.csr.common.exception.BizException;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.vo.resp.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * @Author: yang hao
 * @Date: 2024/11/19 16:21
 * @Description: 归档会话服务
 **/
@Slf4j
@Service
public class ArchiveConversationService {

    @Autowired
    private ArchiveConversationMapper archiveConversationMapper;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ArchiveMessageService archiveMessageService;
    @Autowired
    private CsrImAccountService csrImAccountService;

    /**
     * 分页查询会话
     * @param request {@link ArchiveConversationPageQueryRequest} 分页查询请求
     * @return {@link List<ArchiveConversationResponse>} 归档会话列表
     */
    public PageResponse<ArchiveConversationResponse> page(ArchiveConversationPageQueryRequest request) {
        // 构建分页查询
        Criteria criteria = buildPageQuery(request);
        // 设置分页参数
        int page;
        int size;
        try {
            page = Math.toIntExact(request.getPage()) - 1;
            size = Math.toIntExact(request.getPageSize());
        } catch (Exception e) {
            log.error("分页参数转换失败，page:{},pageSize:{}", request.getPage(), request.getPageSize());
            throw new BizException(StatusCode.Common.ILLEGAL_PARAM_ERROR);
        }
        // 排序
        Sort sort = Sort.by(Sort.Direction.DESC, "conversationStartTime");
        Pageable pageable = PageRequest.of(page, size, sort);
        // 分页查询
        Query query = Query.query(criteria);
        long totalRecords = mongoTemplate.count(query, ArchiveConversation.class);
        List<ArchiveConversation> conversations = mongoTemplate.find(query.with(pageable), ArchiveConversation.class);
        // 将查询结果转换为响应对象列表
        List<ArchiveConversationResponse> records = ConversationArchiveAssembler.convert(conversations);
        return new PageResponse<>(totalRecords, (long)pageable.getPageSize(), (long)pageable.getPageNumber() + 1, records);
    }

    /**
     * 获取会话详情
     * @param id {@link String} 归档会话ID
     * @return {@link ArchiveConversationDetailResponse} 归档会话详情
     */
    public ArchiveConversationDetailResponse detail(String id) {
        ArchiveConversationDetailResponse response = ArchiveConversationDetailResponse.builder().build();
        // 查询会话
        ArchiveConversation conversation = archiveConversationMapper.findById(id).orElse(null);
        if (conversation == null) {
            return response;
        }
        // 查询客服
        CsrImAccount csAccount = csrImAccountService.getById(conversation.getCsAccountId());
        if (csAccount == null) {
            return response;
        }
        // 查询历史消息
        List<ArchiveMessageResponse> messages = archiveMessageService.findByConversationIdAndUserId(conversation.getConversationId(), conversation, csAccount.getAccountUserId(), RequestSource.WEB);
        response.setConversation(ConversationArchiveAssembler.convert(conversation));
        response.setMessages(messages);
        return response;
    }

    /**
     * 获取会话详情
     * @param conversationId {@link String} 会话ID
     * @return {@link ArchiveConversationDetailResponse} 归档会话详情
     */
    public ArchiveConversationDetailResponse detailByConversationId(String conversationId) {
        ArchiveConversationDetailResponse response = ArchiveConversationDetailResponse.builder().build();
        // 查询会话
        ArchiveConversation conversation = getByConversationId(conversationId);
        if (conversation == null) {
            return response;
        }
        // 查询客服
        CsrImAccount csAccount = csrImAccountService.getById(conversation.getCsAccountId());
        if (csAccount == null) {
            return response;
        }
        // 查询历史消息
        List<ArchiveMessageResponse> messages = archiveMessageService.findByConversationIdAndUserId(conversation.getConversationId(), conversation, csAccount.getAccountUserId(), RequestSource.WEB);
        response.setConversation(ConversationArchiveAssembler.convert(conversation));
        response.setMessages(messages);
        return response;
    }

    /**
     * 批量保存会话
     * @param conversations {@link ArchiveConversation} 归档会话
     */
    public void saveBatch(List<ArchiveConversation> conversations) {
        archiveConversationMapper.saveAll(conversations);
    }

    /**
     * 历史消息
     * @param currentConversationId {@link String} 当前会话id
     * @param visitorId {@link String} 访客id
     * @param channelId {@link String} 渠道id
     * @param userId {@link String} 当前用户id
     * @param source {@link RequestSource} 请求源
     * @return {@link List<ArchiveConversationDetailResponse>} 历史消息
     */
    public List<ArchiveMessageResponse> historyMessage(String currentConversationId, String visitorId, String channelId, String userId, RequestSource source) {
        // 拉取当前会话前5条会话
        List<ArchiveConversation> conversations = pushLastConversation(currentConversationId, visitorId, channelId);
        // 加载会话消息
        List<ArchiveMessageResponse> responses = Lists.newArrayList();
        // 客服端获取数据
        for (ArchiveConversation conversation : conversations) {
            String accountId;
            // 用户端获取数据
            if (userId.equals(visitorId)) {
                accountId = conversation.getUserAccountId();
            } else {
                // web端获取数据
                accountId = conversation.getCsAccountId();
            }
            CsrImAccount account = csrImAccountService.getById(accountId);
            List<ArchiveMessageResponse> messages = archiveMessageService.findByConversationIdAndUserId(conversation.getConversationId(), conversation, account.getAccountUserId(), source);
            responses.addAll(messages);
        }
        return responses;
    }

    /**
     * 根据会话ID获取会话
     * @param conversationId {@link String} 会话ID
     * @return {@link ArchiveConversation} 归档会话
     */
    public ArchiveConversation getByConversationId(String conversationId) {
        Query query = Query.query(Criteria.where("conversationId").is(conversationId));
        return mongoTemplate.findOne(query, ArchiveConversation.class);
    }

    /**
     * 根据会话ID列表获取会话
     * @param conversationIds {@link String} 会话ID列表
     * @return {@link List<ArchiveConversation>} 会话列表
     */
    public List<ArchiveConversation> getByConversationIds(List<String> conversationIds) {
        Query query = Query.query(Criteria.where("conversationId").in(conversationIds));
        return mongoTemplate.find(query, ArchiveConversation.class);
    }

    /**
     * 保存会话
     * @param conversation {@link ArchiveConversation} 归档会话
     */
    public void save(ArchiveConversation conversation) {
        archiveConversationMapper.save(conversation);
    }

    /**
     * 拉取最后5条会话
     * @param currentConversationId {@link String} 当前会话ID
     * @param visitorId {@link String} 用户id
     * @param channelId {@link String} 渠道id
     * @return {@link List<ArchiveConversation>} 会话列表
     */
    private List<ArchiveConversation> pushLastConversation(String currentConversationId, String visitorId, String channelId) {
        List<ArchiveConversation> conversations;
        // 获取当前会话，若存在则往前推5条会话，若不存在则为最后5条会话
        ArchiveConversation currentConversation = getByConversationId(currentConversationId);
        if (currentConversation != null) {
            // 获取当前会话时间
            String currentConversationTime = currentConversation.getConversationEndTime();
            // 获取当前会话前5条会话
            Query query = Query.query(Criteria.where("userId").is(visitorId)
                    .and("channelId").is(channelId)
                    .and("conversationEndTime").lt(currentConversationTime));
            query.with(Sort.by(Sort.Direction.DESC, "conversationEndTime")).limit(5);
            conversations =  mongoTemplate.find(query, ArchiveConversation.class);
        } else {
            // 获取最后5条会话
            Query query = Query.query(Criteria.where("userId").is(visitorId)
                    .and("channelId").is(channelId));
            query.with(Sort.by(Sort.Direction.DESC, "conversationEndTime")).limit(5);
            conversations = mongoTemplate.find(query, ArchiveConversation.class);
        }
        // 按conversationEndTime顺序排列
        conversations.sort(Comparator.comparing(ArchiveConversation::getConversationEndTime));
        return conversations;
    }

    /**
     * 构建归档会话分页查询
     * @param request {@link ArchiveConversationPageQueryRequest} 分页查询请求
     * @return {@link Criteria} 查询条件
     */
    private Criteria buildPageQuery(ArchiveConversationPageQueryRequest request) {
        // 构建查询条件
        Criteria criteria = new Criteria();
        // 访客关键字
        if (request.getUserKeyword() != null) {
            criteria.orOperator(
                    Criteria.where("userId").regex(request.getUserKeyword()),
                    Criteria.where("userName").regex(request.getUserKeyword())
            );
        }
        // 人工会话时间范围
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (request.getConversationStartTime() != null || request.getConversationEndTime() != null) {
            String startTime = request.getConversationStartTime() == null
                    ? sdf.format(DateUtil.offsetMonth(request.getConversationEndTime(), -1))
                    : sdf.format(request.getConversationStartTime());
            String endTime = request.getConversationEndTime() == null
                    ? sdf.format(DateUtil.offsetMonth(request.getConversationStartTime(), 1))
                    : sdf.format(request.getConversationEndTime());
            criteria.and("conversationStartTime").gte(startTime).lte(endTime);
        } else {
            // 默认查询最近一个月数据
            Date now = new Date();
            criteria.and("conversationStartTime")
                    .gte(sdf.format(DateUtil.offsetMonth(now, -1)))
                    .lte(sdf.format(now));
        }
        // 渠道id
        if (request.getChannelId() != null) {
            criteria.and("channelId").is(request.getChannelId());
        }
        // 渠道类型
        if (request.getChannelType() != null) {
            criteria.and("channelType").is(request.getChannelType());
        }
        // 渠道名称
        if (request.getChannelName() != null) {
            criteria.and("channelName").regex(request.getChannelName());
        }
        // 渠道业务
        if (request.getChannelService() != null) {
            criteria.and("channelService").regex(request.getChannelService());
        }
        // 客服所属技能组id
        if (request.getSkillSetId() != null) {
            criteria.and("skillSetId").is(request.getSkillSetId());
        }
        // 客服所属技能组名称
        if (request.getSkillSetName() != null) {
            criteria.and("skillSetName").regex(request.getSkillSetName());
        }
        // 会话id
        if (request.getConversationId() != null) {
            criteria.and("conversationId").regex(request.getConversationId());
        }
        // 客服所属部门id
        if (request.getCsDept() != null) {
            criteria.and("csDeptId").in(request.getCsDept());
        }
        // 客服id
        if (request.getCsId() != null) {
            criteria.and("csId").is(request.getCsId());
        }
        // 客服姓名
        if (request.getCsName() != null) {
            criteria.and("csName").regex(request.getCsName());
        }
        // 客服工号
        if (request.getCsJobNumber() != null) {
            criteria.and("csJobNumber").regex(request.getCsJobNumber());
        }
        // 会话类型
        if (request.getConversationType() != null) {
            criteria.and("conversationType").is(request.getConversationType());
        } else {
            // 默认查询人工和智能会话
            criteria.and("conversationType").in(ConversationType.ARTIFICIAL.name(), ConversationType.SMART.name());
        }
        return criteria;
    }

}
